package framework.mvc.servlet;

import framework.mvc.annotation.Action;
import framework.mvc.annotation.Controller;
import framework.mvc.annotation.Result;
import framework.mvc.enu.ResultType;
import framework.util.JsonUtil;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class ActionServlet extends HttpServlet {

    private String basePackage;
    private String encoding;
    private Map<String,Handler> handlers=new HashMap<String,Handler>();


    private class Handler{
        private Object obj;
        private Method method;
        private Action action;

        public Handler() {
        }

        @Override
        public String toString() {
            return obj.getClass().getSimpleName()+"."+method.getName();
        }

        public Handler(Object obj, Method method, Action action) {
            this.obj = obj;
            this.method = method;
            this.action = action;
        }

        public Action getAction() {
            return action;
        }

        public void setAction(Action action) {
            this.action = action;
        }

        public Object getObj() {
            return obj;
        }

        public void setObj(Object obj) {
            this.obj = obj;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }
    }

    @Override
    public void init() throws ServletException {

        try {
            basePackage=getInitParameter("basePackage");
            encoding=getInitParameter("encoding");

            System.out.println("basePackage = " + basePackage);

            // String realPath=getServletContext().getRealPath("");

            String realPath=this.getClass().getClassLoader().getResource("").getPath();


            File dir=new File(realPath+basePackage.replace(".",File.separator));


            //找到所有Action的字节码文件
            File[] files=dir.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.endsWith(".class");
                }
            });

            for (File file : files) {


                String actionClassName=basePackage+"."+file.getName().substring(0,file.getName().lastIndexOf(".class"));
                Class actionClass=Class.forName(actionClassName);

                Controller controller= (Controller) actionClass.getAnnotation(Controller.class);

                //有Controller主键的类是Action
                if(controller!=null){

                    //创建Action对象
                    Object actionObject=actionClass.newInstance();

                    Action classAction= (Action) actionClass.getAnnotation(Action.class);

                    String actionPath="";

                    if(classAction!=null) {
                        actionPath = classAction.path();
                    }

                    //获得Action类中的所有非private的方法，并找出有Action注解的方法
                    Method[] methods=actionClass.getMethods();

                    for (Method method : methods) {

                        Action methodAction=method.getAnnotation(Action.class);

                        if(methodAction==null){
                            continue;
                        }

                        //获得配置的请求路径（真正的路径）
                        String methodPath=actionPath+methodAction.path();


                        //将请求路径=action对象+handler方法缓存+配置
                        Handler handler=new Handler(actionObject,method,methodAction);
                        handlers.put(methodPath,handler);
                    }

                }




            }


            for (Map.Entry<String, Handler> handlerEntry : handlers.entrySet()) {
                System.out.println("handler : " + handlerEntry);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServletException(e);
        }


    }


    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {


        try {
            request.setCharacterEncoding(encoding);


            //解析请求
            String path=request.getServletPath();
            path=path.substring(0,path.lastIndexOf("."));

            //根据path查找配置的handler
            Handler handler=handlers.get(path);

            //当请求不存在对应的handler时
            if(handler==null){
                response.sendError(HttpServletResponse.SC_NOT_FOUND,path+"不存在");
                return;
            }

            Object actionObject=handler.getObj();
            Method handlerMethod=handler.getMethod();
            Action methodAction=handler.getAction();



            //直接转发到jsp页面
            if(!"".equals(methodAction.forward())){
                request.getRequestDispatcher(methodAction.forward()).forward(request,response);
                return;
            }




            //调用处理者方法
            Object handlerResult = handlerMethod.invoke(actionObject,request,response);

            //如果Action中方法返回是null
            if(handlerResult==null){
                return;
            }

            //json处理
            if(!(handlerResult instanceof String)){
                Result[] results=methodAction.results();

                if(results.length==0){
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"result类型不是json");
                    return;
                }

                Result result=results[0];

                if(!ResultType.JSON.equals(result.type())){
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,"result类型不是json");
                    return;
                }

                response.setContentType("application/json;charset="+encoding);

                PrintWriter out=response.getWriter();

                String json=JsonUtil.toJson(handlerResult);

                out.print(json);

                out.flush();
                return;

            }


            //如果handler方法返回值后有?传参
            String param="";
            if(((String)handlerResult).indexOf("?")!=-1){
                String[] s=((String)handlerResult).split("\\?");
                handlerResult=s[0];
                param="?"+s[1];
            }





            Result[] results=methodAction.results();


            Map<String,Result> resultMap=new HashMap<String,Result>();

            for (Result res : results) {
                resultMap.put(res.name(),res);
            }


            //根据处理者方法返回的结果查找对应的Result配置
            Result actionResult=resultMap.get(handlerResult);

            //如果Action中返回的字符串在配置中不存在
            if(actionResult==null){
                response.sendError(HttpServletResponse.SC_NOT_FOUND,handlerResult+"不存在");
                return;
            }


            //根据Result中的type和path生成对应的响应
            if(ResultType.REDIRECT.equals(actionResult.type())){
                response.sendRedirect(request.getContextPath()+actionResult.path()+param);
                return;
            }
            if(ResultType.FORWARD.equals(actionResult.type())){
                request.getRequestDispatcher(actionResult.path()).forward(request,response);
                return;
            }



        } catch (Exception e) {
            e.printStackTrace();
            throw new ServletException(e);
        }












    }
}

















